/*******************************************************************************

    Copyright (C) Device VM Inc. All rights reserved.

    FileName:    ResImage.cpp
    CreateTime:  2009-08-21
    Description: 

    Version history:



*******************************************************************************/


#include "StdAfx.h"
#include "ResImage.h"

using namespace Gdiplus;

ResImage::ResImage()
{
    m_it = NotLoaded;
    m_pImage = NULL;
}

ResImage::~ResImage()
{
    Release();
}

BOOL ResImage::LoadBitmap(UINT nId)
{
    Release();

    if (!m_bmp.LoadBitmap(nId))
    {
        return FALSE;
    }

    if (!m_bmp.GetBitmap(&m_bmInfo))
    {
        return FALSE;
    }

    m_it = Bitmap;

    return TRUE;
}

BOOL ResImage::LoadCustomImage(const CString &strResType, UINT nId)
{
    Release();

    HINSTANCE hInst = AfxGetResourceHandle();
    HRSRC hRes = ::FindResource(hInst, MAKEINTRESOURCE(nId), strResType);

    if (hRes == NULL)
    {
        return FALSE;
    }

    DWORD cbSize = SizeofResource(hInst, hRes);
    BYTE *lpbyRes = (BYTE *)LoadResource(hInst, hRes);

    if (!lpbyRes)
    {
        return FALSE;
    }

    HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, cbSize);
    BYTE *pMem = (BYTE *)GlobalLock(hMem);

    memcpy(pMem, lpbyRes, cbSize);

    IStream *pStream = NULL;
    HRESULT hr = CreateStreamOnHGlobal(hMem, FALSE, &pStream);

    GlobalUnlock(hMem);

    if (!SUCCEEDED(hr) || pStream == NULL)
    {
        return FALSE;
    }

    m_pImage = Image::FromStream(pStream);

    FreeResource(pStream);

    if (m_pImage == NULL)
    {
        return FALSE;
    }

    m_it = CustomImage;

    return TRUE;
}

UINT ResImage::GetWidth()
{
    switch (m_it)
    {
    case Bitmap:
        return m_bmInfo.bmWidth;
    case CustomImage:
        return m_pImage->GetWidth();
    default:
        return 0;
    }
}

UINT ResImage::GetHeight()
{
    switch (m_it)
    {
    case Bitmap:
        return m_bmInfo.bmHeight;
    case CustomImage:
        return m_pImage->GetHeight();
    default:
        return 0;
    }
}

BOOL ResImage::DrawBitmapToDc(CDC &dc, UINT nX /*= 0*/, UINT nY /*= 0*/, UINT nWidth /*= 0*/, UINT nHeight /*= 0*/)
{
    if (m_it != Bitmap)
    {
        return FALSE;
    }

    nWidth == 0 ? nWidth = m_bmInfo.bmWidth : NULL;
    nHeight == 0 ? nHeight = m_bmInfo.bmHeight : NULL;

    CDC dcMem;
    dcMem.CreateCompatibleDC(&dc);
    dcMem.SelectObject(&m_bmp);

    return dc.StretchBlt(nX, nY, nWidth, nHeight, &dcMem, 0, 0, m_bmInfo.bmWidth, m_bmInfo.bmHeight, SRCCOPY);
}

BOOL ResImage::DrawCustomInageToDc(CDC &dc, UINT nX /*= 0*/, UINT nY /*= 0*/, UINT nWidth /*= 0*/, UINT nHeight /*= 0*/)
{
    if (m_it != CustomImage || m_pImage == NULL)
    {
        return FALSE;
    }

    nWidth == 0 ? nWidth = m_pImage->GetWidth() : NULL;
    nHeight == 0 ? nHeight = m_pImage->GetHeight() : NULL;

	// This function uses GDI+ to draw image.
	// When display driver is not well installed, GDI+ cannot support mirroring in RTL-Layout.
	// Here we will creates mirror image along the x-axis manually in RTL-Layout.

	// First turn off default mirroring of original DC and new-created DCs.

	DWORD dwLayout = dc.GetLayout();
	dc.SetLayout(0);

	CDC dcMem, dcMemRTL;
	dcMem.CreateCompatibleDC(&dc);

	CBitmap bmp;
	bmp.CreateCompatibleBitmap(&dc, nWidth, nHeight);
	dcMem.SelectObject(&bmp);

	dcMem.BitBlt(0, 0, nWidth, nHeight, &dc, nX, nY, SRCCOPY);	// Copy background.

	dcMem.SetLayout(0);

	Graphics g(dcMem.GetSafeHdc());
	Rect rectDest(1, 0, nWidth, nHeight);	// The right 1-bit will be cut off in RTL-Layout, so here use 1 as x.

	// Draw image with GDI+.

	if (g.DrawImage(m_pImage, rectDest, 0, 0, m_pImage->GetWidth(), m_pImage->GetHeight(), UnitPixel) != Ok)
	{
		return FALSE;
	}

	// So far the image in memory DC are LTR.

	CDC *pDC = &dcMem;

	if (dwLayout == LAYOUT_RTL)
	{
		// If the environment is RTL, create mirror image.

		dcMemRTL.CreateCompatibleDC(&dc);

		CBitmap bmp;
		bmp.CreateCompatibleBitmap(&dc, nWidth, nHeight);
		dcMemRTL.SelectObject(&bmp);

		dcMemRTL.BitBlt(0, 0, nWidth, nHeight, &dc, nX, nY, SRCCOPY);
		dcMemRTL.SetLayout(0);
		dcMemRTL.StretchBlt(0, 0, nWidth, nHeight, &dcMem, nWidth, 0, -(int)nWidth, nHeight, SRCCOPY);

		pDC = &dcMemRTL;
	}

	// At last turn on default mirroring and copy the image to original DC.

	pDC->SetLayout(dwLayout);
	dc.SetLayout(dwLayout);

    return dc.BitBlt(nX, nY, nWidth, nHeight, pDC, 0, 0, SRCCOPY);
}

BOOL ResImage::DrawToDc(CDC &dc, UINT nX /*= 0*/, UINT nY /*= 0*/, UINT nWidth /*= 0*/, UINT nHeight /*= 0*/)
{
    switch (m_it)
    {
    case Bitmap:
        return DrawBitmapToDc(dc, nX, nY, nWidth, nHeight);
    case CustomImage:
        return DrawCustomInageToDc(dc, nX, nY, nWidth, nHeight);
    default:
        return FALSE;
    }
}

BOOL ResImage::DrawToDcSpecifyTransparent(CDC &dc, COLORREF crTransparent, UINT nX /*= 0*/, UINT nY /*= 0*/, UINT nWidth /*= 0*/, UINT nHeight /*= 0*/)
{
    CDC dcFore, dcMask;
    dcFore.CreateCompatibleDC(&dc);
    dcMask.CreateCompatibleDC(&dc);

    nWidth == 0 ? nWidth = GetWidth() : NULL;
    nHeight == 0 ? nHeight = GetHeight() : NULL;

    CBitmap bmpFore, bmpMask;
    bmpFore.CreateCompatibleBitmap(&dc, nWidth, nHeight);
    bmpMask.CreateBitmap(nWidth, nHeight, 1, 1, NULL);

    dcFore.SelectObject(&bmpFore);
    dcMask.SelectObject(&bmpMask);

    if (!DrawToDc(dcFore, nX, nY, nWidth, nHeight))
    {
        return FALSE;
    }

    dcFore.SetBkColor(crTransparent);
    dcMask.FillSolidRect(0,0,nWidth,nHeight, RGB(255,255,255));
    dcMask.BitBlt(0, 0, nWidth, nHeight, &dcFore, 0, 0, SRCCOPY);

    dcFore.SetBkColor(RGB(0, 0, 0));
    dcFore.SetTextColor(RGB(0xff, 0xff, 0xff));
    dcFore.BitBlt(0, 0, nWidth, nHeight, &dcMask, 0, 0, SRCAND);

    dc.BitBlt(nX, nY, nWidth, nHeight, &dcMask, 0, 0, SRCAND);
    dc.BitBlt(nX, nY, nWidth, nHeight, &dcFore, 0, 0, SRCPAINT);

    return TRUE;
}

void ResImage::Release()
{
    if (m_pImage != NULL)
    {
        delete m_pImage;
        m_pImage = NULL;
    }

    m_it = NotLoaded;
}
